home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C++ / Snippets / AppLauncher 1.0d0 / sources / Shell.cp < prev    next >
Encoding:
Text File  |  1995-10-23  |  14.6 KB  |  655 lines  |  [TEXT/CWIE]

  1. /*
  2. *    jShell.cp
  3. *
  4. *    AppLauncher
  5. *    ^^^^^^^^^^^
  6. *    Main shell for application
  7. *    © Andrew Nemeth (where applicable), Warrimoo Australia 1994, 1995
  8. *    aznemeng@zeta.org.au
  9. *
  10. *    File created:        8 Mar 95.
  11. *    Modified:            8, 9, 12–14, 17, 19 Mar;
  12. *                    19 Apr;
  13. *                    18 Oct 95.
  14. */
  15.  
  16. #include    "gConstDefines.h"                                //     Global #defines & const's
  17. #include    "gVariables.h"                                    //     Global variable defn & 'externs'
  18. #include    "stdHighLevelApple.h"                            //    Application High-Level AE
  19.  
  20. #include    "AZN_DBUG.H"                                    //    debugging utilites
  21. #include    "AZN_TAELaunch.h"                                //    File launching AE utilities
  22.  
  23. #include     <AppleEvents.h>                                //    Mac high level AE
  24. #include    <AEObjects.h>                                    //    mac OSL constants
  25. #include    <LowMem.h>
  26. #include    <Gestalt.h>
  27. #include    <Balloons.h>                                    //    Access to System 7 help menu
  28. #include     <limits.h>                                    //    For LONG_MAX
  29.  
  30.  
  31. //    FILE DEFINES…
  32. //
  33.  
  34. //                                                        'stopMask' parameter in '::FlushEvents()'
  35. const short            kshZapEvents = 0;
  36.  
  37.  
  38. //    PROGRAM GLOBALS
  39. //
  40. struct myGlobalStruct     *gptrGlobalsRec = NULL;
  41.  
  42.  
  43. //    FILE GLOBALS
  44. //
  45. static     MenuHandle    ghMenus[ kMenusInBar ];
  46. static     Boolean        gboolUpdateMenus;
  47. static     RgnHandle        ghMouseRgn;
  48.  
  49. //    Globals used to “tune” the performance of MainEventLoop
  50. //    (assume we’ll be starting in the foreground)
  51.  
  52. static    unsigned long    gulgRunQuantum;
  53. static    unsigned long    gulgSleepQuantum;
  54.  
  55.  
  56.  
  57. //     FILE FUNCTIONS…
  58. //
  59. static void     toolBoxInit        ( void );
  60. static void    assignProgGlobals    ( void );
  61. static void    menuBarInit        ( void );
  62. static void    eventLoop            ( void );
  63. static void    doEvent            ( EventRecord * );
  64. static void    doMouseDown        ( EventRecord * );
  65. static void     doMenuChoice        ( long );
  66. static void     doAppleChoice        ( short );
  67. static void    doFileChoice        ( short );
  68. static void    doOptionsChoice    ( short );
  69. static void    doKeyPress        ( EventRecord * );
  70. static void    maintainMenus        ( Boolean );
  71. static void    quitNow            ( void );
  72.  
  73.  
  74.  
  75. void        main( void )
  76. //
  77. {
  78.     OSErr    myErr;
  79.     long        lgFeature;
  80.  
  81.  
  82.     toolBoxInit();
  83.  
  84.     INIT_DEBUG();
  85. //                                                        MUST be system 7!
  86.     myErr = ::Gestalt( gestaltSystemVersion, &lgFeature );
  87.     if ( myErr == noErr && ( lgFeature < 0x0700 ) ) 
  88.         quitNow();
  89. //                                                        finder must be scriptable!
  90.     myErr = ::Gestalt( gestaltFinderAttr, &lgFeature );
  91.     if ( ( myErr == noErr ) && ( lgFeature & ( 1L << gestaltOSLCompliantFinder ) ) )
  92.         NULL;
  93.     else
  94.         {
  95.         ::StopAlert( kresidALRT_Death, nil );
  96.         quitNow();
  97.         }
  98.  
  99.     assignProgGlobals();
  100.  
  101.     menuBarInit();
  102.  
  103.     eventLoop();    
  104. }
  105.  
  106.  
  107.  
  108. void         toolBoxInit( void )
  109. //
  110. //    Initialise toolbox and memory 
  111. //
  112. {
  113.     ::InitGraf( &qd.thePort );
  114.     ::InitFonts( );
  115.     ::FlushEvents( everyEvent, kshZapEvents );
  116.     ::InitWindows( );
  117.     ::TEInit( );
  118.     ::InitDialogs( 0L );
  119.     ::InitCursor( );
  120. //                                                        cut down on heap fragmentation
  121.     ::MaxApplZone( );
  122.     ::MoreMasters( );
  123.     ::MoreMasters( );
  124. //                                                        fire up for OSL
  125.     if ( ::AEObjectInit() != noErr )
  126.         quitNow();
  127. //                                                        fire up high leve AE
  128.     highLevelEventInit();
  129. }
  130.  
  131.  
  132.  
  133. void        assignProgGlobals( void )
  134. //
  135. //    A single place to assign all
  136. //    program–wide globals
  137. //
  138. {
  139. //                                                        create global struct on heap
  140.     gptrGlobalsRec = (myGlobalStruct *)::NewPtrClear( sizeof( myGlobalStruct ) );
  141.  
  142.     //    Note on the above
  143.     //    Don't use 'gptrGlobalsRec = new struct myGlobalStruct;' !
  144.     //    Operator new in ANSI library allocates blocks of 
  145.     //    memory in 65532 byte slabs.  As this global will be 
  146.     //    hanging around for the entire program, it is
  147.     //    much more efficient to only allocate a ptr of
  148.     //    size 352 bytes (or so).
  149.     //
  150. //                                                        initialise global values
  151.     if ( gptrGlobalsRec )
  152.         {
  153.         gptrGlobalsRec->boolDone = FALSE;
  154. //                                                        event 'tuning' globals
  155.         gptrGlobalsRec->foregroundRunQuantum = 0L;    
  156.         gptrGlobalsRec->foregroundSleepQuantum = GetCaretTime( );
  157.         gptrGlobalsRec->backgroundRunQuantum = 0L;
  158.         gptrGlobalsRec->backgroundSleepQuantum = LONG_MAX;
  159.         }
  160. }
  161.  
  162.  
  163. void         menuBarInit( void )
  164. //
  165. //    Install about menu and then
  166. //    zap all items in menubar
  167. //
  168. {
  169.     MenuHandle    hMenu = NULL;
  170.     Handle        hMenuBar = NULL;
  171.  
  172.  
  173.     hMenuBar = ::GetNewMBar( kMenuBar_ID );
  174.     ASSERT( hMenuBar != nil );
  175.     
  176.     ::SetMenuBar( hMenuBar );
  177. //                                                        assign Global MenuHandle Array
  178.     for ( short i = kAppleNdx, j = kMApple_ID; i < kMenusInBar ; i++, j++ )
  179.         {
  180.         ghMenus[ i ] = (MenuHandle)::GetMenu( j );
  181.         ASSERT( ghMenus[ i ] != nil );
  182.         }
  183. //                                                        insert 'About Application' into apple Menu
  184.     hMenu = ::GetMHandle( kMApple_ID );
  185.     ASSERT( hMenu != nil );
  186.  
  187.     ::AddResMenu( hMenu, 'DRVR' );
  188.  
  189.     ::DrawMenuBar( );
  190.     gboolUpdateMenus = FALSE;
  191. }
  192.  
  193.  
  194.  
  195. void         eventLoop( void )
  196. //
  197. //    Main event handling loop
  198. //
  199. {
  200.     EventRecord        erRec;
  201.     unsigned long        ulgCheckEvents = 0L;
  202.  
  203.  
  204.     gulgRunQuantum = gptrGlobalsRec->foregroundRunQuantum;
  205.     gulgSleepQuantum = gptrGlobalsRec->foregroundSleepQuantum;
  206.     ghMouseRgn = nil;
  207.     gboolUpdateMenus = TRUE;
  208.  
  209.     gptrGlobalsRec->boolDone = FALSE;
  210.  
  211.     while ( ! gptrGlobalsRec->boolDone )
  212.         {
  213.         if ( gulgRunQuantum == 0  || ( ::TickCount( ) > ulgCheckEvents ) )
  214.             {
  215.             ulgCheckEvents = ::TickCount() + gulgRunQuantum;
  216.             ::WaitNextEvent( everyEvent, &erRec, gulgSleepQuantum, ghMouseRgn );
  217.             doEvent( &erRec );
  218.             }
  219.         }
  220. //                                                        final tidy-up prior to exit
  221.     quitNow();
  222. }
  223.  
  224.  
  225.  
  226.  
  227. void         doEvent( EventRecord *ptrEventRec )
  228. //
  229. //    Events are first dealt with here
  230. //    Note: most of these events are processed
  231. //    in the individual dialogFilter procedures!
  232. //
  233. {
  234.     switch ( ptrEventRec->what )
  235.         {
  236. //                                                        null events
  237.         case nullEvent:
  238.             break;
  239. //                                                        see 'stdHighLevelApple.cp'
  240.         case kHighLevelEvent:
  241.             ::AEProcessAppleEvent( ptrEventRec );
  242.             break;
  243. //                                                        key press
  244.         case autoKey:
  245.         case keyDown:
  246.             doKeyPress( ptrEventRec );
  247.             break;
  248. //                                                        rat press
  249.         case mouseDown:
  250.             doMouseDown( ptrEventRec );
  251.             break;
  252. //                                                        not handled
  253.         case activateEvt:
  254.         case updateEvt:
  255.             break;
  256. //                                                        disc insertions
  257.         case diskEvt:
  258.             if ( ptrEventRec->message >> 16 )
  259.                 {
  260.                 static    Point    where = { 50, 50 };
  261.                 ::DIBadMount( where, ptrEventRec->message );
  262.                 }
  263.             break;
  264. //                                                        multi-finder foreground/ background
  265.         case    osEvt:
  266.             switch ( ( ptrEventRec->message & osEvtMessageMask ) >> 24 )
  267.                 {
  268.                 case    mouseMovedMessage:
  269.                     break;
  270.                     
  271.                 case    suspendResumeMessage:                    
  272.                     if ( ptrEventRec->message & resumeFlag )
  273.                         {
  274.                         ::SetCursor( &qd.arrow );
  275.  
  276.                         gulgRunQuantum = gptrGlobalsRec->foregroundRunQuantum;
  277.                         gulgSleepQuantum = gptrGlobalsRec->foregroundSleepQuantum;
  278.                         }
  279.                     else
  280.                         {
  281.                         gulgRunQuantum = gptrGlobalsRec->backgroundRunQuantum;
  282.                         gulgSleepQuantum = gptrGlobalsRec->backgroundSleepQuantum;
  283.                         }
  284.                     break;
  285.                 }
  286.             break;
  287.         }
  288. //                                                        update menus when there's an interesting event
  289.     if ( ptrEventRec->what != nullEvent && gboolUpdateMenus )
  290.         maintainMenus( TRUE );
  291. }
  292.  
  293.  
  294.  
  295. void         doMouseDown( EventRecord  *ptrEventRec )
  296. //
  297. //    Someone squeezed the rat…
  298. //
  299. {
  300.     WindowPtr        ptrWindow;
  301.     short        thePart;
  302.     long            lgMenuChoice;
  303.     
  304.  
  305.     thePart = ::FindWindow( ptrEventRec->where, &ptrWindow );
  306.     switch( thePart )
  307.         {
  308. //                                                        menu selected
  309.         case inMenuBar:
  310.             lgMenuChoice = ::MenuSelect( ptrEventRec->where );
  311.             doMenuChoice( lgMenuChoice );
  312.             break;
  313. //                                                        window dragged about - not handled
  314.         case inDrag:
  315.         case inContent:
  316.             break;
  317. //                                                        DA's
  318.         case inSysWindow:
  319.             ::SystemClick( ptrEventRec, ptrWindow );
  320.             gboolUpdateMenus = TRUE;
  321.             break;
  322.         }
  323. }
  324.  
  325.  
  326.  
  327. void         doMenuChoice( long lgMenuChoice )
  328. //
  329. //    Menu chosen
  330. //
  331. {
  332.     short        menu;
  333.     short        shMenuItem;
  334.     
  335.  
  336.     if ( lgMenuChoice != 0 )
  337.         {
  338. //                                                        Macros to break 4-byte value into 2 shorts
  339.         menu = HiWord( lgMenuChoice ); 
  340.         shMenuItem = LoWord( lgMenuChoice );
  341.             
  342.         switch( menu )
  343.             {
  344.             case kMApple_ID:
  345.                 doAppleChoice( shMenuItem );
  346.                 break;
  347.  
  348.             case kMFile_ID:
  349.                 doFileChoice( shMenuItem );
  350.                 break;
  351.  
  352.             case kMOptions_ID:
  353.                 doOptionsChoice( shMenuItem );
  354.                 break;
  355. //                                                        system 7 Help menu - not handled
  356.             case kHMHelpMenuID:
  357.                 break;
  358. //                                                        catch-all escape to quit application
  359.             default:
  360.                 quitNow( );
  361.                 break;
  362.             }
  363.         ::HiliteMenu( 0 );
  364.         }
  365. }
  366.  
  367.  
  368.  
  369. void         doAppleChoice( short shMenuItem )
  370. //
  371. //    'About Application' chosen or DA
  372. //
  373. {
  374.     MenuHandle    appleMenu = NULL;
  375.     Str255        accName = { kEmptyString };
  376.     short        accNumber;
  377.     
  378.  
  379.     switch ( shMenuItem )
  380.         {
  381.         case kM_About:
  382. //                                                        knockout highlight on apple menu
  383.             ::FlashMenuBar( kMApple_ID );
  384.             ::NoteAlert( kresidALRT_About, kNilFilterProc );
  385.             gboolUpdateMenus = TRUE;
  386.             break;
  387. //                                                        existing Apple Menus
  388.         default:
  389.             appleMenu = ::GetMHandle( kMApple_ID );
  390.             ::GetItem( appleMenu, shMenuItem, accName );
  391.             accNumber = ::OpenDeskAcc( accName );
  392.             gboolUpdateMenus = TRUE;
  393.             break;
  394.         }
  395. }
  396.  
  397.  
  398.  
  399. void        doFileChoice( short shMenuItem )
  400. //
  401. //    Parse 'File' menu choice
  402. //
  403. {
  404.     switch( shMenuItem )
  405.         {
  406. //                                                        signal ready for quit
  407.         case kM_Quit:
  408.         default:
  409.             gptrGlobalsRec->boolDone = TRUE;
  410.             break;
  411.         }
  412. }
  413.  
  414.  
  415.  
  416. void        doOptionsChoice( short shMenuItem )
  417. //
  418. //    Parse 'Options' menu choice
  419. //    Note:  for the following code to work
  420. //    you need to have a copy of 'TeachText'
  421. //    or 'SimpleText' somewhere on one of
  422. //    your drives
  423. //
  424. {
  425.     ConstStr63Param    kstr63AppName = { "\pSimpleText" };
  426. //                                                        the creator for 'SimpleText' application
  427.     const OSType        kostypeAPP = 'ttxt',
  428. //                                                        the creator for 'Date/Time' control panel
  429.                     kostypeCPNL = 'time';
  430.  
  431.     Boolean            boolToFront = FALSE;
  432.     FSSpec            fsspecAPP, 
  433.                     fsspecDOC;
  434.     OSErr            myErr = noErr;
  435.  
  436.  
  437.     switch( shMenuItem )
  438.         {
  439. //    BACKGROUND!
  440. //                                                        launch a remote application
  441.         case kM_LaunchApp_Back:
  442.  
  443.             boolToFront = FALSE;
  444.             myErr = TAELaunch::findApplication( kstr63AppName, kostypeAPP, &fsspecAPP );
  445.             if ( myErr == noErr )
  446.                 {
  447.                 if ( ! TAELaunch::openItemInFinder( fsspecAPP, boolToFront ) )
  448.                     ::SysBeep(1);
  449.                 }
  450.             break;
  451. //                                                        launch app with doc
  452.         case kM_LaunchDoc_Back:
  453.  
  454.             boolToFront = FALSE;
  455. //                                                        assemble FSSpec for readme file in default dir
  456.             myErr = ::FSMakeFSSpec( -LMGetSFSaveDisk(),
  457.                                 LMGetCurDirStore(),
  458.                                 "\pREAD_ME",
  459.                                 &fsspecDOC );
  460.             if (myErr == noErr )
  461.                 {
  462.                 if ( ! TAELaunch::openItemInFinder( fsspecDOC, boolToFront ) )
  463.                     ::SysBeep(1);
  464.                 }
  465.             break;
  466. //                                                        open a doc in already running remote app.
  467.         case kM_OpenDocInRemoteApp_Back:
  468.             boolToFront = FALSE;
  469. //                                                        assemble FSSpec for readme file in default dir
  470.             myErr = ::FSMakeFSSpec( -LMGetSFSaveDisk(),
  471.                                 LMGetCurDirStore(),
  472.                                 "\pREAD_ME",
  473.                                 &fsspecDOC );
  474.             if (myErr == noErr )
  475.                 {
  476.                 if ( ! TAELaunch::openDocInApp( kostypeAPP, fsspecDOC, boolToFront ) )
  477.                     ::SysBeep( 1 );
  478.                 }
  479.             break;
  480.  
  481. //    FOREGROUND!
  482. //                                                        launch a remote application
  483.         case kM_LaunchApp_Fore:
  484.             boolToFront = TRUE;
  485.             myErr = TAELaunch::findApplication( kstr63AppName, kostypeAPP, &fsspecAPP );
  486.             if ( myErr == noErr )
  487.                 {
  488.                 if ( ! TAELaunch::openItemInFinder( fsspecAPP, boolToFront ) )
  489.                     ::SysBeep(1);
  490.                 }
  491.             break;
  492. //                                                        launch app with doc
  493.         case kM_LaunchDoc_Fore:
  494.             boolToFront = TRUE;
  495. //                                                        assemble FSSpec for readme file in default dir
  496.             myErr = ::FSMakeFSSpec( -LMGetSFSaveDisk(),
  497.                                 LMGetCurDirStore(),
  498.                                 "\pREAD_ME",
  499.                                 &fsspecDOC );
  500.             if (myErr == noErr )
  501.                 {
  502.                 if ( ! TAELaunch::openItemInFinder( fsspecDOC, boolToFront ) )
  503.                     ::SysBeep(1);
  504.                 }
  505.             break;
  506. //                                                        open a doc in already running remote app.
  507.         case kM_OpenDocInRemoteApp_Fore:
  508.             boolToFront = TRUE;
  509. //                                                        assemble FSSpec for readme file in default dir
  510.             myErr = ::FSMakeFSSpec( -LMGetSFSaveDisk(),
  511.                                 LMGetCurDirStore(),
  512.                                 "\pREAD_ME",
  513.                                 &fsspecDOC );
  514.             if (myErr == noErr )
  515.                 {
  516.                 if ( ! TAELaunch::openDocInApp( kostypeAPP, fsspecDOC, boolToFront ) )
  517.                     ::SysBeep(1);
  518.                 }
  519.             break;
  520.  
  521. //    OTHER STUFF…
  522. //                                                        hide remote application
  523.         case kM_HideOtherApp:
  524.             TAELaunch::hideProcess( kostypeAPP );
  525.             break;
  526. //                                                        show remote application
  527.         case kM_ShowOtherApp:
  528.             TAELaunch::showProcess( kostypeAPP );
  529.             break;
  530. //                                                        send quit AE to remote application
  531.         case kM_QuitOtherApp:
  532.             TAELaunch::killProcess( kostypeAPP );
  533.             break;
  534. //                                                        the woiks!…
  535.         case kM_DoEverything:
  536.             boolToFront = FALSE;
  537.  
  538.             myErr = ::FSMakeFSSpec( -LMGetSFSaveDisk(),
  539.                                 LMGetCurDirStore(),
  540.                                 "\pREAD_ME",
  541.                                 &fsspecDOC );
  542. //                                                        open up doc in finder…
  543.             if (myErr == noErr )
  544.                 {
  545.                 if ( ! TAELaunch::openItemInFinder( fsspecDOC, boolToFront ) )
  546.                     ::SysBeep(1);
  547.                 }
  548. //                                                        now hide application…
  549.             TAELaunch::hideProcess( kostypeAPP );
  550. //                                                        put up an ALRT…
  551.             ::SetCursor( &qd.arrow );
  552.             ::NoteAlert( kresidALRT_About, kNilFilterProc );
  553. //                                                        now show it again!
  554.             TAELaunch::showProcess( kostypeAPP );
  555.             break;
  556. //                                                        open a control panel
  557.         case kM_OpenControlPnl:
  558.             if ( ! TAELaunch::openControlPanel( kostypeCPNL ) )
  559.                 ::SysBeep(1);
  560.             break;
  561. //                                                        catch-all in case of stupidity!
  562.         default:
  563.             quitNow();
  564.             break;
  565.         }
  566.  
  567.     gboolUpdateMenus = TRUE;
  568. }
  569.  
  570.  
  571.  
  572. void        doKeyPress( EventRecord *ptrEventRec  )
  573. //
  574. //    Respond to cmd-'' keypresses
  575. //
  576. {
  577.     register char        chCharPressed;
  578.  
  579.  
  580.     chCharPressed = ptrEventRec->message & charCodeMask;
  581.  
  582.     if ( ( ptrEventRec->modifiers & cmdKey ) != 0 )
  583.         {
  584. //                                                        quit now 'cmd-/' key press
  585.         if ( chCharPressed == '/' && ptrEventRec->modifiers & cmdKey )
  586.             quitNow( );
  587.         else
  588.             doMenuChoice( MenuKey( chCharPressed ) );
  589.         }
  590. }
  591.  
  592.  
  593.  
  594. void        maintainMenus( Boolean boolEnableAll )
  595. //
  596. //    Make sure menus reflect 
  597. //    current state of application
  598. //    If 'boolEnableAll' is FALSE, then menubar
  599. //    is deactivated
  600. //
  601. {
  602.     const short    kshDoForAll = 0;
  603.     short    i;
  604.  
  605.  
  606.     //    Enable/ disable all menu bar headings
  607.     //
  608.     for ( i = kAppleNdx; i < kMenusInBar ; i++ )
  609.         {
  610.         if ( boolEnableAll )
  611.             ::EnableItem( ghMenus[ i ], kshDoForAll );
  612.         else
  613.             ::DisableItem( ghMenus[ i ], kshDoForAll );
  614.         }
  615.  
  616. //                                                        enable/ disable individual items
  617.     if ( boolEnableAll )
  618.         {
  619. //                                                        always activate
  620.         ::EnableItem( ghMenus[ kFileNdx ], kM_Quit );
  621.  
  622.         ::DisableItem( ghMenus[ kOptionsNdx ], kBackground_Heading );
  623.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_LaunchApp_Back );
  624.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_LaunchDoc_Back );
  625.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_OpenDocInRemoteApp_Back );
  626.  
  627.         ::DisableItem( ghMenus[ kOptionsNdx ], kForeground_Heading );
  628.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_LaunchApp_Fore );
  629.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_LaunchDoc_Fore );
  630.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_OpenDocInRemoteApp_Fore );
  631.  
  632.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_QuitOtherApp );
  633.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_HideOtherApp );
  634.         ::EnableItem( ghMenus[ kOptionsNdx ], kM_OpenControlPnl );
  635. //                                                        wait for update!
  636.         ::InvalMenuBar( );
  637.         }
  638. //                                                        deactivate mbar NOW!
  639.     else
  640.         ::DrawMenuBar( );
  641.  
  642.     gboolUpdateMenus = FALSE;
  643. }
  644.  
  645.  
  646.  
  647. void        quitNow( void )
  648. //
  649. //    When the cmd—'/' is pressed,
  650. //    things to do before exit
  651. //
  652. {
  653.     ::ExitToShell( );
  654. }
  655.